package com.shiro.demo.framework.shiro;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import net.sf.ehcache.CacheManager;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.event.EventBus;
import org.apache.shiro.event.support.DefaultEventBus;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.session.mgt.SessionFactory;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.SimpleSessionFactory;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.ShiroEventBusBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroWebConfiguration;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class ShiroWebConfig extends ShiroWebConfiguration {
    //会话验证间隔
    @Value("#{ @environment['shiro.sessionManager.sessionValidationInterval'] ?: 3600000L }")
    protected long sessionValidationInterval;
    //全局会话超时时间
    @Value("#{ @environment['shiro.sessionManager.globalSessionTimeout'] ?: 1800000L }")
    protected long globalSessionTimeout;

    /**
     * 构造函数，初始化EnCache
     */
    public ShiroWebConfig(){
        //EhCache实现
        CacheManager cacheManager = CacheManager.getCacheManager("shiro");
        //Shiro包装
        EhCacheManager ehCacheManager = new EhCacheManager();
        if(cacheManager == null){
            ehCacheManager.setCacheManagerConfigFile("classpath:ehcache/ehcache-shiro.xml");
        } else {
            ehCacheManager.setCacheManager(cacheManager);
        }

        this.cacheManager = ehCacheManager;
    }

    /**
     * 配置账户信息
     * @param dataSource
     * @return
     */
    @Bean
    public Realm realm(DataSource dataSource){
        JdbcRealm realm = new JdbcRealm();
        realm.setDataSource(dataSource);

        realm.setSaltStyle(JdbcRealm.SaltStyle.COLUMN);
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("MD5");
        matcher.setHashIterations(5);
        matcher.setStoredCredentialsHexEncoded(true);
        realm.setCredentialsMatcher(matcher);

        return realm;
    }

    /**
     * 会话工厂
     * @return
     */
    protected SessionFactory sessionFactory() {
        return new SimpleSessionFactory();
    }

    /**
     * 自定义ShiroSessionManager
     * @return
     */
    protected SessionManager nativeSessionManager() {
        DefaultWebSessionManager webSessionManager = new DefaultWebSessionManager();
        webSessionManager.setSessionIdCookieEnabled(this.sessionIdCookieEnabled);
        webSessionManager.setSessionIdUrlRewritingEnabled(this.sessionIdUrlRewritingEnabled);
        webSessionManager.setSessionIdCookie(this.sessionCookieTemplate());
        webSessionManager.setSessionFactory(this.sessionFactory());
        webSessionManager.setSessionDAO(this.sessionDAO());
        webSessionManager.setDeleteInvalidSessions(this.sessionManagerDeleteInvalidSessions);
        webSessionManager.setGlobalSessionTimeout(this.globalSessionTimeout);
        webSessionManager.setSessionValidationInterval(this.sessionValidationInterval);
        return webSessionManager;
    }

    /**
     * 会话仓库
     * @return
     */
    protected SessionDAO sessionDAO() {
        return new EnterpriseCacheSessionDAO();
    }

    /**
     * 定义Url-Filters
     * @return
     */
    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();

        chainDefinition.addPathDefinition("/secured/**", "user");
        chainDefinition.addPathDefinition("/logout", "logout");
        chainDefinition.addPathDefinition("/login", "captchaAuthFilter, formAuthenticationFilter");
        chainDefinition.addPathDefinition("/**", "anon");

        return chainDefinition;
    }

    /**
     * 开启Shiro注解通知器
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
            @Qualifier("securityManager") SecurityManager securityManager)
    {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 控制Shiro组件生命周期
     * --不能使用本PostBean，打开批注将导致无法注入属性？？？？？
     * @return
     */
    //@Bean
    LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 给其它组件注入EventBus
     * @return
     */
    @Bean
    ShiroEventBusBeanPostProcessor shiroEventBusBeanPostProcessor(){
        return new ShiroEventBusBeanPostProcessor(eventBus());
    }

    /**
     * EventBus实例
     * @return
     */
    @Bean
    public EventBus eventBus(){
        return new DefaultEventBus();
    }

    /**
     * thymeleaf模板引擎和shiro框架的整合
     */
    @Bean
    public ShiroDialect shiroDialect()
    {
        return new ShiroDialect();
    }
}
